﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace SBPweb.PROvibe.Shared.Utilities.Collections
{

    public class OverridableList<TItem> : IList<TItem>
    {

        #region Private fields

        private List<TItem> list = new List<TItem>();

        #endregion

        #region Property accessors

        public TItem this[int index]
        {
            get
            {
                return list[index];
            }
            set
            {
                list[index] = value;
            }
        }

        public IEnumerable<TItem> Items
        {
            get
            {
                return list;
            }
            set
            {
                if (ItemRemoved != null)
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        ItemRemoved(this, new ListItemEventArgs<TItem>(i, list[i]));
                    }
                }
                if (value is List<TItem>)
                {
                    list = value as List<TItem>;
                }
                else
                {
                    list = new List<TItem>(value);
                }
                if (ItemAdded != null)
                {
                    for (int i = 0; i < list.Count; i++)
                    {
                        ItemAdded(this, new ListItemEventArgs<TItem>(i, list[i]));
                    }
                }
            }
        }

        public int Count
        {
            get
            {
                return list.Count;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        #endregion

        #region Events

        public event EventHandler<ListItemEventArgs<TItem>> ItemAdded;

        public event EventHandler<ListItemEventArgs<TItem>> ItemRemoved;

        #endregion

        #region Methods

        public virtual void Add(TItem item)
        {
            list.Add(item);
            if (ItemAdded != null)
            {
                ItemAdded(this, new ListItemEventArgs<TItem>(list.IndexOf(item), item));
            }
        }

        public virtual void AddRange(IEnumerable<TItem> items)
        {
            foreach (TItem item in items)
            {
                this.Add(item);
            }
        }

        public virtual void Clear()
        {
            foreach (TItem item in list)
            {
                this.Remove(item);
            }
            list.Clear();
        }

        public bool Contains(TItem item)
        {
            return list.Contains(item);
        }

        public void CopyTo(TItem[] array, int arrayIndex)
        {
            list.CopyTo(array, arrayIndex);
        }

        public IList<TItem> GetRange(int index, int count)
        {
            return list.GetRange(index, Count);
        }

        public int IndexOf(TItem item)
        {
            return list.IndexOf(item);
        }

        public virtual void Insert(int index, TItem item)
        {
            list.Insert(index, item);
            if (ItemAdded != null)
            {
                ItemAdded(this, new ListItemEventArgs<TItem>(index, item));
            }
        }

        public virtual bool Remove(TItem item)
        {
            int index = list.IndexOf(item);
            bool ret = list.Remove(item);
            if (ret && ItemRemoved != null)
            {
                ItemRemoved(this, new ListItemEventArgs<TItem>(index, item));
            }
            return ret;
        }

        public virtual void RemoveAt(int index)
        {
            TItem item = list[index];
            list.RemoveAt(index);
            if (ItemRemoved != null)
            {
                ItemRemoved(this, new ListItemEventArgs<TItem>(index, item));
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return list.GetEnumerator();
        }

        public IEnumerator<TItem> GetEnumerator()
        {
            return list.GetEnumerator();
        }

        #endregion

    }

}